#ifndef GAMEENGINE_GEOMETRY_POLYGON3D_H
#define GAMEENGINE_GEOMETRY_POLYGON3D_H

#include <GameEngine/Geometry/geometry_settings.h>

#include <GameEngine/Geometry/Location/point3d.h>
#include <GameEngine/Geometry/Lines/line3d.h>
#include <GameEngine/Geometry/Surfaces/trgl3d.h>
#include <GameEngine/Geometry/Surfaces/trgl3dfast.h>
#include <GameEngine/Geometry/Surfaces/plane3d.h>

#include <vector>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif


//! Class used to represent 3D polygons
/*!
 *  No restriction is imposed on the type of polygon that can be represented: convex
 *  or concave polygons, planar polygons, etc.
 *
 @note A 3D polygon is made of a set of 3D points
 @note Most algorithms expect floating point operations. Type T should therefore
       not be an integer type
 @todo Setup unit tests
 */
template <class T>
class Polygon3d {

public:
	//! Typedef used to handle point indexes in the polygon
	typedef unsigned int PointIndex;
	//! Typedef used to handle the number of points in the polygon
	typedef unsigned int PointCount;

	Polygon3d();
	Polygon3d(const Trgl3d<T>& rhs);
	Polygon3d(const Trgl3dFast<T>& rhs);
	Polygon3d(const Parallelogram3d<T>& rhs);
	virtual ~Polygon3d();
	Polygon3d& operator=(const Polygon3d& rhs);

	Point3d<T>* p(PointIndex index);
	const Point3d<T>* p(PointIndex index) const;
	Point3d<T>& operator[](PointIndex index);
	const Point3d<T>& operator[](PointIndex index) const;

	PointIndex add_point(const Point3d<T>& pt, PointIndex* after_index = nil);
	PointCount remove_point(const Point3d<T>& pt, const T& tolerance = 0.000001);
	PointIndex find_point(const Point3d<T>& pt, const T& tolerance = 0.000001, PointIndex* from = nil) const;
	PointCount nb_points() const;

	Vector3d<T> normal() const;

//	bool planar(const T& tolerance = 0.000001) const;
//	bool inside(const Point3d<T>& rhs, bool strict = false) const;
//	bool intersection(const Line3d<T>& rhs, T& line_coordinate, IntersectionType::Type* type = nil) const;
//	Point3d<T> closest_point(const Point3d<T>& rhs) const;

	T perimeter() const;
	T area() const;

//	bool degenerate(const T& tolerance = 0.000001) const;

//	Plane3d<T> plane() const;

protected:
	//! Point coordinates
	std::vector< Point3d<T> > points_;
};

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#include <GameEngine/Geometry/Surfaces/polygon3d.hpp>

#endif
